using System;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Xml.Linq;
using System.Xml.Serialization;
using Microsoft.SharePoint;
using System.Collections.Generic;
using DE.Sdc.SharePoint.SPContentStructure.Common;
#if SP_Server
using Microsoft.SharePoint.Portal;
using DE.Sdc.SharePoint.SPContentStructure.Common;
#endif


namespace DE.Sdc.SharePoint.SPContentStructure.Import
{
    [Serializable]
    [XmlType(AnonymousType = true, Namespace = DeploymentConstants.Namespace)]
    [XmlRoot(Namespace = DeploymentConstants.Namespace, IsNullable = false)]
    public class List : Folder, IImportDefinition<SPList, SPWeb>
    {
        public List()
            : base()
        {
            Fields = new Fields();
            Views = new Views();
            ContentTypes = new ContentTypes();
        }

        /// <remarks/>
        [XmlAttribute]
        public string PrimaryKeyFields { get; set; }

        [XmlIgnore]
        public string[] PrimaryKeyFieldsArray
        {
            get
            {
                if (string.IsNullOrEmpty(PrimaryKeyFields))
                    return null;

                return PrimaryKeyFields.Split(new[] { ';', ',' }, StringSplitOptions.RemoveEmptyEntries);
            }
        }

        [XmlAttribute]
        public string UniqueFields { get; set; }

        [XmlIgnore]
        public string[] UniqueFieldsArray
        {
            get
            {
                if (string.IsNullOrEmpty(UniqueFields))
                    return null;

                return UniqueFields.Split(new[] { ';', ',' }, StringSplitOptions.RemoveEmptyEntries);
            }
        }

        /// <remarks/>
        [XmlAttribute]
        public string Description { get; set; }

        /// <remarks/>
        [XmlAttribute]
        public string FeatureId { get; set; }

        /// <remarks/>
        [XmlAttribute]
        public int TemplateId { get; set; }

        /// <remarks/>
        [XmlAttribute]
        public int DocTemplateId { get; set; }

        /// <remarks/>
        [XmlAttribute]
        public bool NoCrawl { get; set; }

        /// <remarks/>
        [XmlAttribute]
        public bool EnableModeration { get; set; }

        /// <remarks/>
        [XmlAttribute]
        public bool EnableContentTypes { get; set; }

        /// <remarks/>
        [XmlAttribute]
        public bool EnableVersioning { get; set; }

        /// <remarks/>
        [XmlAttribute]
        public bool EnableMinorVersions { get; set; }

        /// <remarks/>
        [XmlAttribute]
        public bool EnableAttachments { get; set; }

        /// <remarks/>
        [XmlAttribute]
        public bool EnableFolderCreation { get; set; }

        /// <remarks/>
        [XmlAttribute]
        public bool EnableRatings { get; set; }

        /// <remarks/>
        [XmlAttribute]
        public bool UndoFileCheckout { get; set; }

        /// <remarks/>
        [XmlElement(typeof(Fields))]
        public Fields Fields { get; set; }

        [XmlIgnore]
        public bool FieldsSpecified
        {
            get
            {
                return Fields != null && Fields.Items.Count > 0;
            }
        }

        /// <remarks/>
        [XmlElement(typeof(ContentTypes))]
        public ContentTypes ContentTypes { get; set; }

        [XmlIgnore]
        public bool ContentTypesSpecified
        {
            get
            {
                return ContentTypes != null && ContentTypes.Items.Count > 0;
            }
        }

        [XmlElement(typeof(Views))]
        public Views Views { get; set; }

        [XmlIgnore]
        public bool ViewsSpecified
        {
            get
            {
                return Views != null && Views.Items.Count > 0;
            }
        }

        [XmlIgnore]
        public new SPList UpdatedSPObject { get; internal set; }

        

        //[XmlArrayItem("PowerShell", typeof(Powershell))]
        //public List<Powershell> PowerShellNodes { get; set; }

        /// <summary>
        /// Creates a list in a given web
        /// </summary>
        /// <param name="parentWeb">The parent web where to create the list</param>
        /// <returns>The created list</returns>
        private SPList CreateList(SPWeb parentWeb)
        {
            string listName = DeploymentHelper.Resolve(Title, parentWeb.Locale);
            string listDescription = DeploymentHelper.Resolve(Description, parentWeb.Locale);
            string listUrl = DeploymentHelper.Resolve(Url, parentWeb.Locale);

            Trace.WriteLine("Try to create list '" + listName + "' with url '" + AbsoluteUrl + "'.", "ContentStructureImporter:CreateList");

            Guid listId = parentWeb.Lists.Add(listName, listDescription,
                                              listUrl ?? listName, FeatureId,
                                              TemplateId == 0 ? 100 : TemplateId,
                                              DocTemplateId == 0
                                                  ? "100"
                                                  : DocTemplateId.ToString());

            Trace.WriteLine("List '" + listName + "' with url '" + AbsoluteUrl + "' created.", "ContentStructureImporter:CreateList");
            return parentWeb.Lists[listId];
        }

        /// <summary>
        /// Modifies the properties for a list 
        /// </summary>
        /// <param name="list">The list which properties should updated</param>
        private void UpdateList(SPList list)
        {
            Trace.WriteLine("Try to modify list '" + Title + "' with url '" + AbsoluteUrl + "'.", "ContentStructureImporter:UpdateList");
            //using (SPWeb parentWeb = list.ParentWeb)
            //{
            list.NoCrawl = NoCrawl;
            list.EnableModeration = EnableModeration;
            list.EnableAttachments = EnableAttachments;
            list.EnableFolderCreation = EnableFolderCreation;
            list.EnableVersioning = EnableVersioning;
            list.EnableMinorVersions = EnableMinorVersions;
            list.ContentTypesEnabled = EnableContentTypes;

#if SP_Server
                if (EnableRatings)
                {
                    // activite rating features 
                    SPWeb rootWeb = list.ParentWeb.Site.RootWeb;
                    Guid ratingFeatureId = new Guid("915c240e-a6cc-49b8-8b2c-0bff8b553ed3");
                    SPFeature ratingFeature = rootWeb.Site.Features[ratingFeatureId];
                    if (ratingFeature == null)
                    {
                        rootWeb.Site.AllowUnsafeUpdates = true;
                        rootWeb.AllowUnsafeUpdates = true;
                        SPFeatureCollection featureCollect = rootWeb.Site.Features;
                        ratingFeature = featureCollect.Add(ratingFeatureId, true);
                        rootWeb.Update();
                        rootWeb.AllowUnsafeUpdates = false;
                        rootWeb.Site.AllowUnsafeUpdates = false;
                    }

             
                }
#endif

            ModifyObjectProperties(list);

            list.Update();
            //}
            Trace.WriteLine("List '" + Title + "' with url '" + AbsoluteUrl + "'. modified", "ContentStructureImporter:UpdateList");
        }

        /// <summary>
        /// Deletes a list
        /// </summary>
        /// <param name="list">The list to delete</param>
        private void DeleteList(SPList list)
        {
            Trace.WriteLine("Try to delete list '" + list.Title + "' with url '" + list.ParentWebUrl + "'.", "ContentStructureImporter:DeleteList");
            try
            {
                list.Delete();
            }
            catch (SPException ex)
            {
                Trace.WriteLine("List '" + list.Title + "' with url '" + list.ParentWebUrl + "' cannot be deleted. " + ex.Message, "ContentStructureImporter:DeleteList");
                Trace.WriteLine("Try to cleanup list '" + list.Title + "' with url '" + list.ParentWebUrl + "'.", "ContentStructureImporter:DeleteList");
#if !SP_07     
                for (int index = 0; index < list.Fields.Count; index++)
                {
                    SPField field = list.Fields[index];
                    if (field is SPFieldLookup && ((SPFieldLookup)field).RelationshipDeleteBehavior == SPRelationshipDeleteBehavior.Cascade)
                    {

                        Trace.WriteLine("Field '" + field.Title + "' with id '" + field.Id + "' will be deleted.", "ContentStructureImporter:DeleteList");
                        field.Delete();
                        Trace.WriteLine("Field '" + field.Title + "' with id '" + field.Id + "' is deleted.", "ContentStructureImporter:DeleteList");
                        index--;
                }
                }

                list.Delete();
#else
                throw ex;
#endif
            }
            Trace.WriteLine("List '" + list.Title + "' with url '" + list.ParentWebUrl + "' deleted.", "ContentStructureImporter:DeleteList");

        }

        /// <summary>
        /// Adds, Replaces, Deletes, Modifies or Moves a list in a given web
        /// </summary>
        /// <param name="list">A list based on the listDefinition or null</param>
        /// <param name="parentWeb">The parent where to import the list</param>
        public void ImportDefinition(SPList list, SPWeb parentWeb)
        {
            Trace.WriteLine("Try to import list '" + Title + "' with url '" + AbsoluteUrl + "'.", "ContentStructureImporter:ImportList");

            if (list == null)
            {
                if (Action == ActionType.AddOrUpdate || Action == ActionType.Replace)
                    list = CreateList(parentWeb);
                else
                    return;
            }
            else if (Action == ActionType.Replace && IsNewVersion(list.RootFolder))
            {
                DeleteList(list);
                list = CreateList(parentWeb);
            }
            else if (Action == ActionType.Delete)
            {
                DeleteList(list);
                return;
            }

            SetNewVersion(list.RootFolder);

            DeploymentContext.Current.List = list;
            DeploymentContext.Current.ListDefinition = this;
            DeploymentContext.Current.CurrentObjectType = DeploymentContext.DeploymentObjects.List;

            if (Action != ActionType.None &&
                Action <= ActionType.AddOrUpdateOrReplace)
                UpdateList(list);

            

            Fields.ImportDefinition(list, list.ParentWeb);
            Views.ImportDefinition(list, list.ParentWeb);
            ContentTypes.ImportDefinition(list, list.ParentWeb);

            if ((UniqueFieldsArray != null) && (UniqueFieldsArray.Length == 1))
#if SP_07
#else
               DeploymentHelper.SetEnforceUniqueValues(list, UniqueFieldsArray[0]);
#endif


                DeploymentContext.Current.Folder = list.RootFolder;
            DeploymentContext.Current.FolderDefinition = this;
            DeploymentContext.Current.CurrentObjectType = DeploymentContext.DeploymentObjects.Folder;

            //For importing versions we are temporarily enabling moderation on the current list (this bit actually happens when
            //importing a version for an list item). We do this so we can set the Author/Modified/Created(At) properties when approving 
            //documents/items. If we do not enable moderation, saving item properties for the last version will generate a new version
            //which was not present in the import file. After processing is completed, the original setting is restored.
            var hasVersions = HasItemVersions();
            var moderation = list.EnableModeration;
            if (hasVersions && !list.EnableModeration && list.EnableMinorVersions)
            {
                list.EnableModeration = true;
                list.Update();
            }

            try
            {
                ImportDefinition(list.RootFolder, null);
            }
            finally
            {
                list = parentWeb.Lists.GetList(list.ID, true);
                if (list.EnableModeration != moderation && list.EnableMinorVersions)
                {
                    list.EnableModeration = moderation;
                }
            }

            

            list.Update();
            DeploymentContext.Current.CurrentObjectType = DeploymentContext.DeploymentObjects.List;

                        

            Trace.WriteLine("List '" + Title + "' with url '" + AbsoluteUrl + "'.", "ContentStructureImporter:ImportList");
            UpdatedSPObject = list;

        }

        private bool HasItemVersions()
        {
            var serializer = new XmlSerializer(typeof(List));
            var writer = new StringWriter();

            serializer.Serialize(writer, this);

            var ns = XNamespace.Get("http://sdc/2009/07/Deployment/1.1/ContentStructure");
            var root = XElement.Parse(writer.ToString());

            return (root.Descendants(ns + "Versions").Any());
        }
    }
}